﻿using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.AnimatedValues;
using UnityEngine;

namespace CWM.Skinn
{
    public class SkinnCommandWindow : EditorWindow
    {
        public const string Description = "The command browsers is a overview of available context commands." +
                "Right-Click a component's header to access and execute commands, use this window to explore context commands.";

        public static SkinnCommandWindow commandWindow;

        [MenuItem("Window/Skinn/Command Browser")]
        public static void ShowWindow()
        {
            if (commandWindow) commandWindow.Close();
            commandWindow = (SkinnCommandWindow)EditorWindow.GetWindow(typeof(SkinnCommandWindow));
#if UNITY_2017_1_OR_NEWER
            commandWindow.titleContent = new GUIContent("Skinn CB");
#else
            commandWindow.title = "Skinn CB";
#endif
        }

        private static Vector2 scroll = Vector2.zero;

        private class CommandGroup
        {
            public string group;
            public AnimBool enabled;
            public Dictionary<string, CommandSubGroup> items;
        }

        private class CommandSubGroup
        {
            public string group;
            public AnimBool enabled;
            public List<CtxMenuItem> items;
        }

        private static Dictionary<string, CommandGroup> contextGroups;
        private static Dictionary<string, CommandGroup> GetContextGroups
        {
            get { if (contextGroups == null) contextGroups = ContextGroups(); return contextGroups; }
        }

        public static void RepaintWindow() { if (commandWindow) commandWindow.Repaint(); }

        public void OnEnable() { commandWindow = this; }


        public void OnGUI()
        {
            SkinnGUIHeader.GUIHeader(new GUIContent("Skinn Command Browser ", string.Format("{0} commands", CommmandCount)), MonoScript.FromScriptableObject(this));

            var groups = GetContextGroups;
            var indentLevel = EditorGUI.indentLevel;
            GUILayout.Label(Description, EditorStyles.helpBox);

            scroll = EditorGUILayout.BeginScrollView(scroll);
            foreach (var group in groups)
            {
                EditorGUI.indentLevel = indentLevel;
                group.Value.enabled.target = EditorGUILayout.Foldout(group.Value.enabled.target, group.Value.group);
                EditorGUI.indentLevel = indentLevel + 1;
                if (EditorGUILayout.BeginFadeGroup(group.Value.enabled.faded))
                {
                    EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                    var subGroups = group.Value.items;
                    foreach (var subGroup in subGroups)
                    {
                        EditorGUI.indentLevel = indentLevel + 1;
                        if (subGroup.Value.items.Count > 0)//1
                            subGroup.Value.enabled.target = EditorGUILayout.Foldout(subGroup.Value.enabled.target, subGroup.Value.group);
                        else EditorGUILayout.Foldout(true, subGroup.Value.group);

                        if (EditorGUILayout.BeginFadeGroup(subGroup.Value.enabled.faded))
                        {
                            EditorGUI.indentLevel = indentLevel + 2;
                            var menuItems = subGroup.Value.items;
                            for (int i = 0; i < menuItems.Count; i++)
                            {
                                EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                                var label = menuItems[i].menuItem.Replace(group.Key + "/", "");
                                using (new EditorGUI.DisabledScope(true))
                                {
                                    if (GUILayout.Button(label, GUI.skin.button)) { }
                                }
                                var info = menuItems[i].tooltip;
                                EditorGUILayout.LabelField(info, EditorStyles.wordWrappedLabel);
                                EditorGUILayout.EndVertical();
                            }
                        }
                        EditorGUILayout.EndFadeGroup();
                    }
                    EditorGUILayout.EndVertical();
                }
                EditorGUILayout.EndFadeGroup();
            }
            EditorGUILayout.EndScrollView();
            EditorGUI.indentLevel = indentLevel;
        }

        private static int CommmandCount = 0;

        private static Dictionary<string, List<CtxMenuItem>> RawGroups()
        {
            var methods = typeof(SkinnContextCommands).GetMethods();
            var ctxItems = new Dictionary<string, List<CtxMenuItem>>();

            CommmandCount = 0;
            string all = "";
            foreach (var method in methods)
            {
                var attributes = method.GetCustomAttributes(true);

                for (int i = 0; i < attributes.Length; i++)
                {
                    var ctxItem = attributes[i] as CtxMenuItem; if (!ctxItem) continue;
                    var ctxType = ctxItem.menuItem.Remove(ctxItem.menuItem.IndexOf("/"));

                    if (ctxItem.flags != ContextFlag.Header)
                    {
                        CommmandCount++;
                        //all += " <p>";
                        all += ctxItem.menuItem;// + "  :  " + ctxItem.tooltip;
                        //all += " <p>";

                        //all += System.Environment.NewLine;
                        all += System.Environment.NewLine;
                    }

                    List<CtxMenuItem> items;
                    if (ctxItems.TryGetValue(ctxType, out items))
                    { ctxItems.Remove(ctxType); items.Add(ctxItem); ctxItems.Add(ctxType, items); }
                    else ctxItems.Add(ctxType, new List<CtxMenuItem> { ctxItem });
                }
            }
            if(all == "")  { }
            //Debug.Log(all);

            return ctxItems;
        }

        private static Dictionary<string, CommandGroup> ContextGroups()
        {
            if (contextGroups == null)
            {
                contextGroups = new Dictionary<string, CommandGroup>();
                var groups = RawGroups();
                foreach (var catagory in groups)
                {
                    var subclasses = new Dictionary<string, CommandSubGroup>();
                    var items = catagory.Value;
                    for (int i = 0; i < items.Count; i++)
                    {
                        var id = items[i].menuItem;
                        if (items[i].flags == ContextFlag.Header) continue;
                        var ctxType = id.Split('/').ToList();
                        if (ctxType.Count > 2)
                        {
                            ctxType.RemoveAt(0);
                            ctxType.RemoveAt(ctxType.Count - 1);
                            id = string.Join("/", ctxType.ToArray());
                        }
                        else if (ctxType.Count < 1)
                        {
                            ctxType.RemoveAt(0);
                            id = string.Join("/", ctxType.ToArray());
                        }

                        CommandSubGroup subitems;
                        if (subclasses.TryGetValue(id, out subitems))
                        {
                            subitems.items.Add(items[i]);
                            subclasses.Remove(id);
                            subclasses.Add(id, subitems);
                        }
                        else
                        {
                            var isEnabled = new AnimBool(false);

                            isEnabled.valueChanged.AddListener(RepaintWindow);
                            var commandSubGroup = new CommandSubGroup()
                            {
                                enabled = isEnabled,
                                group = id,
                                items = new List<CtxMenuItem>() { items[i] }
                            };
                            subclasses.Add(id, commandSubGroup);
                        }
                    }

                    var enabled = new AnimBool(true);
                    enabled.valueChanged.AddListener(RepaintWindow);
                    var commandGroup = new CommandGroup() { enabled = enabled, group = catagory.Key, items = subclasses };
                    contextGroups.Add(catagory.Key, commandGroup);
                }

            }
            return contextGroups;
        }


    }
}